{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "前面对权重参数进行初始化时，使用的均是服从标准差为0.1的正太分布的参数，下面更换权重初始化函数运行看结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"A very simple MNIST classifier.\n",
    "See extensive documentation at\n",
    "https://www.tensorflow.org/get_started/mnist/beginners\n",
    "\"\"\"\n",
    "from __future__ import absolute_import\n",
    "from __future__ import division\n",
    "from __future__ import print_function\n",
    "\n",
    "import argparse\n",
    "import sys\n",
    "\n",
    "from tensorflow.examples.tutorials.mnist import input_data\n",
    "\n",
    "import tensorflow as tf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./MNIST/train-images-idx3-ubyte.gz\n",
      "Extracting ./MNIST/train-labels-idx1-ubyte.gz\n",
      "Extracting ./MNIST/t10k-images-idx3-ubyte.gz\n",
      "Extracting ./MNIST/t10k-labels-idx1-ubyte.gz\n"
     ]
    }
   ],
   "source": [
    "# 导入数据\n",
    "data_dir = './MNIST'\n",
    "mnist = input_data.read_data_sets(data_dir, one_hot=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "#定义数据\n",
    "x = tf.placeholder(tf.float32, [None, 784])   # 输入图片的大小，28x28=784\n",
    "y_ = tf.placeholder(tf.float32, [None, 10])   # 输出0-9共10个数字\n",
    "learning_rate = tf.placeholder(tf.float32)    # 用于接收dropout操作的值，dropout为了防止过拟合\n",
    "\n",
    "with tf.name_scope('reshape'):\n",
    "#-1代表先不考虑输入的图片例子多少这个维度，后面的1是channel的数量，因为我们输入的图片是黑白的，因此channel是1，例如如果是RGB图像，那么channel就是3\n",
    "  x_image = tf.reshape(x, [-1, 28, 28, 1])    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "#from keras.layers.initializers import he_normal\n",
    "# 卷积层定义\n",
    "#函数参数中的filter_size是指卷积核的大小,step表示布长\n",
    "#这里使用函数tf.contrib.layers.variance_scaling_initializer来对权重参数进行He/MRSA初始化，更改参数可以实现Xavier初始化\n",
    "def conv_op(input_op, filter_size, channel_out, name):\n",
    "    h_conv1 = tf.layers.conv2d(input_op, channel_out, [filter_size,filter_size],\n",
    "                             padding='SAME',\n",
    "                             activation=tf.nn.relu,name=name,kernel_initializer=tf.contrib.layers.variance_scaling_initializer())    \n",
    "    return h_conv1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 最大池化层\n",
    "def maxPool_op(input_op, filter_size, step, name):\n",
    "    h_pool1 = tf.layers.max_pooling2d(input_op, pool_size=[filter_size,filter_size],\n",
    "                        strides=[step, step], padding='VALID',name=name)\n",
    "    return h_pool1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"\\ndef full_connection(input_op, channel_out, name):\\n    channel_in = input_op.get_shape()[-1].value\\n    with tf.name_scope(name) as scope:\\n        weight = tf.Variable(tf.truncated_normal([channel_in, channel_out],mean=0,\\n                                                  dtype=tf.float32, stddev=0.1),\\n                                                  collections=[tf.GraphKeys.GLOBAL_VARIABLES,'WEIGHTS'])\\n        #weight = tf.get_variable(shape=[channel_in, channel_out], dtype=tf.float32,\\n        #                         initializer=xavier_initializer_conv2d(), name=scope + 'weight')\\n        bias = tf.Variable(tf.constant(value=0.0, shape=[channel_out], dtype=tf.float32), name='bias')\\n        input_op_reshape = tf.reshape(input_op, [-1, 7 * 7 * 64])\\n        fc = tf.nn.relu(tf.matmul(input_op_reshape, weight) + bias)\\n        return fc\\n\""
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 全连接层\n",
    "'''\n",
    "def full_connection(input_op, channel_out, name):\n",
    "    channel_in = input_op.get_shape()[-1].value\n",
    "    with tf.name_scope(name) as scope:\n",
    "        weight = tf.Variable(tf.truncated_normal([channel_in, channel_out],mean=0,\n",
    "                                                  dtype=tf.float32, stddev=0.1),\n",
    "                                                  collections=[tf.GraphKeys.GLOBAL_VARIABLES,'WEIGHTS'])\n",
    "        #weight = tf.get_variable(shape=[channel_in, channel_out], dtype=tf.float32,\n",
    "        #                         initializer=xavier_initializer_conv2d(), name=scope + 'weight')\n",
    "        bias = tf.Variable(tf.constant(value=0.0, shape=[channel_out], dtype=tf.float32), name='bias')\n",
    "        input_op_reshape = tf.reshape(input_op, [-1, 7 * 7 * 64])\n",
    "        fc = tf.nn.relu(tf.matmul(input_op_reshape, weight) + bias)\n",
    "        return fc\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "#第一层卷积层，卷积核为5*5，深度为32，步长为1，输出为28*28*32\n",
    "conv1=conv_op(x_image,filter_size=5,channel_out=32,name='conv1')\n",
    "#第一个池化层，输出14*14*28\n",
    "pool1=maxPool_op(conv1,filter_size=2,step=2,name='pool1')\n",
    "#第二层卷积层，卷积核为5*5，深度为64，步长为1，输出为28*28*64\n",
    "conv2=conv_op(pool1,filter_size=5,channel_out=64,name='conv2')\n",
    "#第二个池化层，输出7*7*64\n",
    "pool2=maxPool_op(conv2,filter_size=2,step=2,name='pool2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tensorflow.contrib.layers import flatten\n",
    "#全连接层，映射7*7*64特征图，映射为1024个特征\n",
    "with tf.name_scope('fc1'):\n",
    "  h_pool2_flat = flatten(pool2)\n",
    "  h_fc1 = tf.layers.dense(h_pool2_flat, 1024, activation=tf.nn.relu)\n",
    "\n",
    "# Dropout - controls the complexity of the model, prevents co-adaptation of\n",
    "# features.\n",
    "with tf.name_scope('dropout'):\n",
    "  keep_prob = tf.placeholder(tf.float32)\n",
    "  h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)\n",
    "\n",
    "# Map the 1024 features to 10 classes, one for each digit\n",
    "#这里同上，需要注意的是，最后暂不需要使用激活函数\n",
    "with tf.name_scope('fc2'):\n",
    "  y = tf.layers.dense(h_fc1_drop, 10, activation=None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 设置正则化方法\n",
    "REGULARIZATION_RATE = 0.0001 # 比较合适的参数\n",
    "\n",
    "regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)  # 定义L2正则化损失函数\n",
    "#regularization = regularizer(weights1) + regularizer(weights2)  # 计算模型的正则化损失"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "step 100, entropy loss: 0.506006, l2_loss: 0.087969, total loss: 0.593976\n",
      "0.91\n",
      "step 200, entropy loss: 0.454942, l2_loss: 0.088042, total loss: 0.542984\n",
      "0.86\n",
      "step 300, entropy loss: 0.189965, l2_loss: 0.088083, total loss: 0.278048\n",
      "0.96\n",
      "step 400, entropy loss: 0.217130, l2_loss: 0.088112, total loss: 0.305241\n",
      "0.95\n",
      "step 500, entropy loss: 0.291735, l2_loss: 0.088135, total loss: 0.379870\n",
      "0.94\n",
      "step 600, entropy loss: 0.168797, l2_loss: 0.088156, total loss: 0.256953\n",
      "0.97\n",
      "step 700, entropy loss: 0.145848, l2_loss: 0.088173, total loss: 0.234021\n",
      "0.95\n",
      "step 800, entropy loss: 0.223193, l2_loss: 0.088188, total loss: 0.311381\n",
      "0.95\n",
      "step 900, entropy loss: 0.154750, l2_loss: 0.088194, total loss: 0.242944\n",
      "0.94\n",
      "step 1000, entropy loss: 0.101032, l2_loss: 0.088205, total loss: 0.189237\n",
      "0.99\n",
      "0.959\n",
      "step 1100, entropy loss: 0.168712, l2_loss: 0.088213, total loss: 0.256925\n",
      "0.96\n",
      "step 1200, entropy loss: 0.178427, l2_loss: 0.088222, total loss: 0.266649\n",
      "0.96\n",
      "step 1300, entropy loss: 0.204314, l2_loss: 0.088229, total loss: 0.292543\n",
      "0.96\n",
      "step 1400, entropy loss: 0.174580, l2_loss: 0.088234, total loss: 0.262814\n",
      "0.95\n",
      "step 1500, entropy loss: 0.172136, l2_loss: 0.088236, total loss: 0.260373\n",
      "0.98\n",
      "step 1600, entropy loss: 0.078226, l2_loss: 0.088237, total loss: 0.166464\n",
      "0.98\n",
      "step 1700, entropy loss: 0.116402, l2_loss: 0.088239, total loss: 0.204641\n",
      "0.98\n",
      "step 1800, entropy loss: 0.109709, l2_loss: 0.088243, total loss: 0.197952\n",
      "0.98\n",
      "step 1900, entropy loss: 0.110226, l2_loss: 0.088243, total loss: 0.198469\n",
      "0.98\n",
      "step 2000, entropy loss: 0.089324, l2_loss: 0.088244, total loss: 0.177568\n",
      "0.99\n",
      "0.9702\n",
      "step 2100, entropy loss: 0.118495, l2_loss: 0.088245, total loss: 0.206740\n",
      "0.96\n",
      "step 2200, entropy loss: 0.069674, l2_loss: 0.088244, total loss: 0.157917\n",
      "0.97\n",
      "step 2300, entropy loss: 0.075288, l2_loss: 0.088244, total loss: 0.163532\n",
      "0.98\n",
      "step 2400, entropy loss: 0.086257, l2_loss: 0.088241, total loss: 0.174497\n",
      "0.99\n",
      "step 2500, entropy loss: 0.138615, l2_loss: 0.088238, total loss: 0.226852\n",
      "0.97\n",
      "step 2600, entropy loss: 0.149977, l2_loss: 0.088236, total loss: 0.238213\n",
      "0.98\n",
      "step 2700, entropy loss: 0.054546, l2_loss: 0.088235, total loss: 0.142781\n",
      "0.96\n",
      "step 2800, entropy loss: 0.095341, l2_loss: 0.088231, total loss: 0.183572\n",
      "0.97\n",
      "step 2900, entropy loss: 0.156916, l2_loss: 0.088228, total loss: 0.245144\n",
      "0.98\n",
      "step 3000, entropy loss: 0.033299, l2_loss: 0.088225, total loss: 0.121524\n",
      "0.99\n",
      "0.9773\n",
      "step 3100, entropy loss: 0.036873, l2_loss: 0.088222, total loss: 0.125095\n",
      "0.99\n",
      "step 3200, entropy loss: 0.124182, l2_loss: 0.088219, total loss: 0.212401\n",
      "0.97\n",
      "step 3300, entropy loss: 0.044916, l2_loss: 0.088215, total loss: 0.133130\n",
      "0.99\n",
      "step 3400, entropy loss: 0.100581, l2_loss: 0.088211, total loss: 0.188791\n",
      "0.98\n",
      "step 3500, entropy loss: 0.107386, l2_loss: 0.088206, total loss: 0.195592\n",
      "0.97\n",
      "step 3600, entropy loss: 0.018687, l2_loss: 0.088201, total loss: 0.106888\n",
      "1.0\n",
      "step 3700, entropy loss: 0.073595, l2_loss: 0.088197, total loss: 0.161793\n",
      "0.97\n",
      "step 3800, entropy loss: 0.061189, l2_loss: 0.088191, total loss: 0.149380\n",
      "0.98\n",
      "step 3900, entropy loss: 0.062586, l2_loss: 0.088186, total loss: 0.150772\n",
      "1.0\n",
      "step 4000, entropy loss: 0.062446, l2_loss: 0.088180, total loss: 0.150626\n",
      "0.98\n",
      "0.98\n",
      "step 4100, entropy loss: 0.044547, l2_loss: 0.088175, total loss: 0.132721\n",
      "0.98\n",
      "step 4200, entropy loss: 0.081248, l2_loss: 0.088170, total loss: 0.169419\n",
      "0.98\n",
      "step 4300, entropy loss: 0.028211, l2_loss: 0.088164, total loss: 0.116375\n",
      "1.0\n",
      "step 4400, entropy loss: 0.022217, l2_loss: 0.088156, total loss: 0.110373\n",
      "1.0\n",
      "step 4500, entropy loss: 0.045276, l2_loss: 0.088150, total loss: 0.133425\n",
      "1.0\n",
      "step 4600, entropy loss: 0.017957, l2_loss: 0.088144, total loss: 0.106101\n",
      "0.99\n",
      "step 4700, entropy loss: 0.046765, l2_loss: 0.088137, total loss: 0.134902\n",
      "0.99\n",
      "step 4800, entropy loss: 0.025596, l2_loss: 0.088131, total loss: 0.113727\n",
      "1.0\n",
      "step 4900, entropy loss: 0.035951, l2_loss: 0.088125, total loss: 0.124076\n",
      "0.99\n",
      "step 5000, entropy loss: 0.062949, l2_loss: 0.088119, total loss: 0.151068\n",
      "1.0\n",
      "0.9813\n",
      "step 5100, entropy loss: 0.150786, l2_loss: 0.088113, total loss: 0.238898\n",
      "0.98\n",
      "step 5200, entropy loss: 0.187310, l2_loss: 0.088105, total loss: 0.275415\n",
      "0.95\n",
      "step 5300, entropy loss: 0.042683, l2_loss: 0.088097, total loss: 0.130780\n",
      "0.98\n",
      "step 5400, entropy loss: 0.072157, l2_loss: 0.088091, total loss: 0.160248\n",
      "0.98\n",
      "step 5500, entropy loss: 0.068829, l2_loss: 0.088083, total loss: 0.156912\n",
      "0.98\n",
      "step 5600, entropy loss: 0.030437, l2_loss: 0.088076, total loss: 0.118514\n",
      "1.0\n",
      "step 5700, entropy loss: 0.069886, l2_loss: 0.088069, total loss: 0.157954\n",
      "0.97\n",
      "step 5800, entropy loss: 0.069027, l2_loss: 0.088061, total loss: 0.157088\n",
      "0.97\n",
      "step 5900, entropy loss: 0.035401, l2_loss: 0.088052, total loss: 0.123453\n",
      "0.97\n",
      "step 6000, entropy loss: 0.061891, l2_loss: 0.088044, total loss: 0.149934\n",
      "0.99\n",
      "0.9832\n",
      "step 6100, entropy loss: 0.039066, l2_loss: 0.088038, total loss: 0.127104\n",
      "1.0\n",
      "step 6200, entropy loss: 0.034558, l2_loss: 0.088030, total loss: 0.122589\n",
      "0.98\n",
      "step 6300, entropy loss: 0.034845, l2_loss: 0.088023, total loss: 0.122868\n",
      "0.99\n",
      "step 6400, entropy loss: 0.034835, l2_loss: 0.088014, total loss: 0.122849\n",
      "0.96\n",
      "step 6500, entropy loss: 0.072144, l2_loss: 0.088007, total loss: 0.160150\n",
      "0.98\n",
      "step 6600, entropy loss: 0.023028, l2_loss: 0.087997, total loss: 0.111025\n",
      "0.99\n",
      "step 6700, entropy loss: 0.060727, l2_loss: 0.087989, total loss: 0.148715\n",
      "0.99\n",
      "step 6800, entropy loss: 0.055046, l2_loss: 0.087981, total loss: 0.143027\n",
      "0.99\n",
      "step 6900, entropy loss: 0.055289, l2_loss: 0.087972, total loss: 0.143261\n",
      "0.99\n",
      "step 7000, entropy loss: 0.123458, l2_loss: 0.087964, total loss: 0.211421\n",
      "0.97\n",
      "0.9851\n",
      "step 7100, entropy loss: 0.074684, l2_loss: 0.087956, total loss: 0.162640\n",
      "0.99\n",
      "step 7200, entropy loss: 0.065230, l2_loss: 0.087947, total loss: 0.153177\n",
      "0.99\n",
      "step 7300, entropy loss: 0.059999, l2_loss: 0.087939, total loss: 0.147938\n",
      "0.99\n",
      "step 7400, entropy loss: 0.056926, l2_loss: 0.087929, total loss: 0.144855\n",
      "0.98\n",
      "step 7500, entropy loss: 0.011536, l2_loss: 0.087921, total loss: 0.099457\n",
      "1.0\n",
      "step 7600, entropy loss: 0.006909, l2_loss: 0.087912, total loss: 0.094821\n",
      "1.0\n",
      "step 7700, entropy loss: 0.024808, l2_loss: 0.087903, total loss: 0.112710\n",
      "1.0\n",
      "step 7800, entropy loss: 0.094673, l2_loss: 0.087894, total loss: 0.182567\n",
      "0.99\n",
      "step 7900, entropy loss: 0.021649, l2_loss: 0.087883, total loss: 0.109532\n",
      "0.99\n",
      "step 8000, entropy loss: 0.064972, l2_loss: 0.087874, total loss: 0.152846\n",
      "0.99\n",
      "0.9841\n",
      "step 8100, entropy loss: 0.016217, l2_loss: 0.087865, total loss: 0.104082\n",
      "1.0\n",
      "step 8200, entropy loss: 0.038056, l2_loss: 0.087855, total loss: 0.125912\n",
      "0.99\n",
      "step 8300, entropy loss: 0.050213, l2_loss: 0.087847, total loss: 0.138060\n",
      "0.99\n",
      "step 8400, entropy loss: 0.032859, l2_loss: 0.087838, total loss: 0.120696\n",
      "0.99\n",
      "step 8500, entropy loss: 0.022897, l2_loss: 0.087828, total loss: 0.110726\n",
      "1.0\n",
      "step 8600, entropy loss: 0.033050, l2_loss: 0.087819, total loss: 0.120869\n",
      "0.97\n",
      "step 8700, entropy loss: 0.026776, l2_loss: 0.087811, total loss: 0.114587\n",
      "1.0\n",
      "step 8800, entropy loss: 0.058569, l2_loss: 0.087801, total loss: 0.146369\n",
      "0.99\n",
      "step 8900, entropy loss: 0.064987, l2_loss: 0.087791, total loss: 0.152778\n",
      "0.99\n",
      "step 9000, entropy loss: 0.043679, l2_loss: 0.087782, total loss: 0.131461\n",
      "0.97\n",
      "0.9857\n",
      "step 9100, entropy loss: 0.033765, l2_loss: 0.087771, total loss: 0.121536\n",
      "0.98\n",
      "step 9200, entropy loss: 0.021042, l2_loss: 0.087763, total loss: 0.108805\n",
      "1.0\n",
      "step 9300, entropy loss: 0.032140, l2_loss: 0.087753, total loss: 0.119894\n",
      "1.0\n",
      "step 9400, entropy loss: 0.051468, l2_loss: 0.087745, total loss: 0.139213\n",
      "0.99\n",
      "step 9500, entropy loss: 0.008132, l2_loss: 0.087735, total loss: 0.095867\n",
      "1.0\n",
      "step 9600, entropy loss: 0.031667, l2_loss: 0.087726, total loss: 0.119394\n",
      "0.97\n",
      "step 9700, entropy loss: 0.055038, l2_loss: 0.087717, total loss: 0.142754\n",
      "0.98\n",
      "step 9800, entropy loss: 0.027837, l2_loss: 0.087707, total loss: 0.115544\n",
      "0.99\n",
      "step 9900, entropy loss: 0.017845, l2_loss: 0.087695, total loss: 0.105540\n",
      "0.99\n",
      "step 10000, entropy loss: 0.014728, l2_loss: 0.087685, total loss: 0.102413\n",
      "1.0\n",
      "0.9877\n"
     ]
    }
   ],
   "source": [
    "cross_entropy = tf.reduce_mean(\n",
    "    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))\n",
    "regularization=0.0\n",
    "for w in tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES):\n",
    "    regularization=regularization+regularizer(w)\n",
    "l2_loss=regularization\n",
    "#l2_loss = tf.add_n( [tf.nn.l2_loss(w) for w in tf.get_collection('WEIGHTS')] )\n",
    "#total_loss = cross_entropy + 7e-5*l2_loss\n",
    "total_loss = cross_entropy + l2_loss\n",
    "train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(total_loss)\n",
    "\n",
    "sess = tf.Session()\n",
    "init_op = tf.global_variables_initializer()\n",
    "sess.run(init_op)\n",
    "# Train\n",
    "for step in range(10000):\n",
    "  batch_xs, batch_ys = mnist.train.next_batch(100)\n",
    "  lr = 0.01\n",
    "  _, loss, l2_loss_value, total_loss_value = sess.run(\n",
    "               [train_step, cross_entropy, l2_loss, total_loss], \n",
    "               feed_dict={x: batch_xs, y_: batch_ys, learning_rate:lr, keep_prob:0.5})\n",
    "  \n",
    "  if (step+1) % 100 == 0:\n",
    "    print('step %d, entropy loss: %f, l2_loss: %f, total loss: %f' % \n",
    "            (step+1, loss, l2_loss_value, total_loss_value))\n",
    "    # Test trained model\n",
    "    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))\n",
    "    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))\n",
    "    print(sess.run(accuracy, feed_dict={x: batch_xs, y_: batch_ys, keep_prob:0.5}))\n",
    "  if (step+1) % 1000 == 0:\n",
    "    print(sess.run(accuracy, feed_dict={x: mnist.test.images,\n",
    "                                    y_: mnist.test.labels, keep_prob:0.5}))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "心得与小结:\n",
    "我们知道针对权重参数初始化的方法有很多，而一般比较推荐的是Xavier和MSRA两种。Xavier初始化可以帮助减少梯度弥散问题， 使得信号在神经网络中可以传递得更深。是最为常用的神经网络权重初始化方法。一般的神经网络在前向传播时神经元输出值的方差会不断增大,而使用Xavier等方法理论上可以保证每层神经元输入输出方差一致。 而Xavier适用于tanh之类的对称函数，而如果使用Relu函数，合适的选择是HE/MSRA初始化。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里从数据可以看出，这里的训练结果比前面使用正太分布的权重参数更快的达到98%的准确率。step=4000时，准确率就达到了98%"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
